/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package etherblocks.engine.network;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import etherblocks.game.*;
import etherblocks.game.entitysystem.*;
import etherblocks.game.entitysystem.components.*;
import etherblocks.engine.*;
import etherblocks.engine.network.handlers.*;
import etherblocks.engine.network.messages.*;
import etherblocks.engine.states.*;
import com.cubes.Block;
import com.cubes.BlockManager;
import com.cubes.network.*;

/**
 *
 * @author Carl
 */
public class GameServer{

    public GameServer(){
        
    }
    protected NetworkServer networkServer;
    protected World world;
    protected HashMap<Integer, Entity> playerEntities = new HashMap<Integer, Entity>();

    public void onGameStarted(){
        
    }
    
    protected void addEntitySystem(EntitySystem entitySystem){
        EntitySystemAppState entitySystemAppState = getMainApplication().getStateManager().getState(EntitySystemAppState.class);
        entitySystemAppState.addEntitySystem(entitySystem);
    }

    public MessageResponse getMessageResponse(int clientID, NetworkMessage receivedMessage){
        MessageResponse messageResponse = new MessageResponse();
        Entity playerEntity = playerEntities.get(clientID);
        if((receivedMessage instanceof Message_Player) && (playerEntity != null)){
            if(receivedMessage instanceof Message_PlayerState){
                Message_PlayerState message = (Message_PlayerState) receivedMessage;
                playerEntity.setComponent(new LocationComponent(message.getLocation(), System.currentTimeMillis()));
                playerEntity.setComponent(new RotationComponent(message.getViewDirection(), System.currentTimeMillis()));
                AnimationComponent animationComponent;
                if(message.isMoving()){
                    animationComponent = new AnimationComponent("walk", 2.5f);
                }
                else{
                    animationComponent = new AnimationComponent("stand", 1);
                }
                playerEntity.setComponent(animationComponent);
            }
        }
        else if(receivedMessage instanceof Message_BlockSetCommand){
            Message_BlockSetCommand message = (Message_BlockSetCommand) receivedMessage;
            if(!world.isBlockCollidingWithPlayers(message.getX(), message.getY(), message.getZ())){
                setBlock(message.getX(), message.getY(), message.getZ(), BlockManager.getClass(message.getBlockType()));
            }
        }
        else if(receivedMessage instanceof Message_BlockRemoveCommand){
            Message_BlockRemoveCommand message = (Message_BlockRemoveCommand) receivedMessage;
            removeBlock(message.getX(), message.getY(), message.getZ());
        }
        else if(receivedMessage instanceof Message_ClientConnection){
            Message_ClientConnection message = (Message_ClientConnection) receivedMessage;
            if(message.isConnected()){
                playerEntity = world.getEntityMap().createNewEntity();
                EntityTemplate.loadTemplate(playerEntity, "player");
                playerEntities.put(clientID, playerEntity);
                messageResponse.addAnswerMessage(new Message_ConnectionSuccessful(playerEntity.getID()));
                byte[][][][] blockChunksData = CubesSerializer.writeChunksToBytes(world.getBlockTerrain());
                for(int x=0;x<blockChunksData.length;x++){
                    for(int y=0;y<blockChunksData[x].length;y++){
                        for(int z=0;z<blockChunksData[x][y].length;z++){
                            byte[][] chunkPartsData = Util.splitArray(blockChunksData[x][y][z], BlockChunkMessageHandler.MESSAGES_PER_CHUNK);
                            for(int i=0;i<chunkPartsData.length;i++){
                                messageResponse.addAnswerMessage(new Message_BlockChunk(x, y, z, chunkPartsData[i]));
                            }
                        }
                    }
                }
                ConcurrentHashMap<Integer, ConcurrentHashMap<Class, Object>> components = world.getEntityMap().getComponents();
                Integer[] entityIDs = components.keySet().toArray(new Integer[0]);
                Arrays.sort(entityIDs);
                for(int i=0;i<entityIDs.length;i++){
                    int entityID = entityIDs[i];
                    messageResponse.addAnswerMessage(new Message_EntityAdded(entityID));
                    ConcurrentHashMap<Class, Object> entityComponents = components.get(entityID);
                    Iterator<Class> iteratorComponentClass = entityComponents.keySet().iterator();
                    while(iteratorComponentClass.hasNext()){
                        Class componentClass = iteratorComponentClass.next();
                        Object component = entityComponents.get(componentClass);
                        messageResponse.addAnswerMessage(new Message_EntityComponentAdded(entityID, component));
                    }
                }
                messageResponse.addAnswerMessage(new Message_ConnectionFinished());
            }
        }
        return messageResponse;
    }

    public void setNetworkServer(NetworkServer networkServer){
        this.networkServer = networkServer;
    }

    public World getWorld(){
        return world;
    }

    public void setWorld(World world){
        this.world = world;
        world.getEntityMap().addListener(new EntityMapListener(){

            @Override
            public void onEntityAdded(int entityID){
                networkServer.sendMessage(new Message_EntityAdded(entityID));
            }

            @Override
            public void onEntityRemoved(int entityID){
                networkServer.sendMessage(new Message_EntityRemoved(entityID));
            }

            @Override
            public void onComponentAdded(int entityID, Object component){
                networkServer.sendMessage(new Message_EntityComponentAdded(entityID, component));
            }

            @Override
            public void onComponentRemoved(int entityID, Object component){
                networkServer.sendMessage(new Message_EntityComponentRemoved(entityID, component));
            }
        });
    }
    
    protected void setBlock(int x, int y, int z, Class<? extends Block> blockClass){
        world.getBlockTerrain().setBlock(x, y, z, blockClass);
        networkServer.sendMessage(new Message_BlockSetEvent(x, y, z, BlockManager.getType(blockClass).getType()));
    }
    
    protected void removeBlock(int x, int y, int z){
        world.getBlockTerrain().removeBlock(x, y, z);
        networkServer.sendMessage(new Message_BlockRemoveEvent(x, y, z));
    }
    
    protected MainApplication getMainApplication(){
        return networkServer.getGameClient().getMainApplication();
    }
}
